package org.dromara.hm.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.service.CustomerService;
import org.dromara.common.core.service.DeptService;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.helper.DataPermissionHelper;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.hm.domain.HmCustomer;
import org.dromara.hm.domain.HmCustomerTransferHistory;
import org.dromara.hm.domain.HmOrderTransferHistory;
import org.dromara.hm.domain.HmSaleOrder;
import org.dromara.hm.domain.HmTodoItems;
import org.dromara.hm.domain.HmTodoTransferHistory;
import org.dromara.hm.domain.bo.HmCustomerBatchTransferBo;
import org.dromara.hm.domain.bo.HmCustomerBo;
import org.dromara.hm.domain.bo.HmFamilyBo;
import org.dromara.hm.domain.bo.HmSaleOrderBo;
import org.dromara.hm.domain.vo.HmCustomerVo;
import org.dromara.hm.domain.vo.HmFamilyVo;
import org.dromara.hm.domain.vo.HmPurchaseVo;
import org.dromara.hm.domain.vo.saleOrder.HmSaleOrderPickUpVo;
import org.dromara.hm.domain.vo.saleOrder.HmSaleOrderVo;
import org.dromara.hm.domain.vo.HmStaffTransferVo;
import org.dromara.hm.domain.vo.StaffVo;
import org.dromara.hm.mapper.HmCustomerMapper;
import org.dromara.hm.mapper.saleOrder.HmSaleOrderPickUpMapper;
import org.dromara.hm.service.IHmCustomerService;
import org.dromara.hm.service.IHmCustomerTransferHistoryService;
import org.dromara.hm.service.IHmFamilyService;
import org.dromara.hm.service.IHmOrderTransferHistoryService;
import org.dromara.hm.service.IHmSaleOrderService;
import org.dromara.hm.service.IHmTodoItemsService;
import org.dromara.hm.service.IHmTodoTransferHistoryService;
import org.dromara.system.domain.vo.SysDeptVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.service.ISysDeptService;
import org.dromara.system.service.ISysUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 客户信息Service业务层处理
 *
 * @author zy Hu
 * @date 2024-12-15
 */
@RequiredArgsConstructor
@Service
@Slf4j
public class HmCustomerServiceImpl implements IHmCustomerService, CustomerService
{

    private final HmCustomerMapper baseMapper;

    /**
     * 销售Service
     */
    @Lazy
    private final IHmSaleOrderService saleOrderService;

    /**
     * 回款提货Mapper
     */
    private final HmSaleOrderPickUpMapper saleOrderPickUpMapper;

    /**
     * 回访代办记录
     */
    private final IHmTodoItemsService todoItemsService;

    private final DeptService deptService;

    private final IHmFamilyService familyService;

    private final IHmCustomerTransferHistoryService customerTransferHistoryService;

    private final ISysUserService sysUserService;

    private final ISysDeptService sysDeptService;

    private final IHmOrderTransferHistoryService orderTransferHistoryService;

    private final IHmTodoTransferHistoryService todoTransferHistoryService;
    /**
     * 新增客户信息
     *
     * @param bo 客户信息

    /**
     * 查询客户信息
     *
     * @param customerId 主键
     *
     * @return 客户信息
     */
    @Override

    public HmCustomerVo queryById(Long customerId)
    {
        return baseMapper.selectVoById(customerId);
    }

    /**
     * 分页查询客户信息列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     *
     * @return 客户信息分页列表
     */
    @Override
    public TableDataInfo<HmCustomerVo> queryPageList(HmCustomerBo bo, PageQuery pageQuery)
    {
        LambdaQueryWrapper<HmCustomer> lqw = buildQueryWrapper(bo);
        Page<HmCustomerVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的客户信息列表
     *
     * @param bo 查询条件
     *
     * @return 客户信息列表
     */
    @Override
    public List<HmCustomerVo> queryList(HmCustomerBo bo)
    {
        LambdaQueryWrapper<HmCustomer> lqw = buildQueryWrapper(bo);
        List<HmCustomerVo> hmCustomerVos = baseMapper.selectVoList(lqw);
        hmCustomerVos.forEach(hmCustomerVo ->
        {
            // 客户所属部门
            if (StringUtils.isEmpty(hmCustomerVo.getStoreName()) || StringUtils.isEmpty(hmCustomerVo.getStaffName()))
            {
                // 查询客户所属店铺名称
                String storeName = deptService.selectDeptNameByIds(hmCustomerVo.getStoreId().toString());
                hmCustomerVo.setStoreName(storeName);
                // 查询服务人员名称
                SysUserVo sysUserVo = sysUserService.selectUserById(hmCustomerVo.getStaffId());
                if (sysUserVo == null)
                {
                    hmCustomerVo.setStaffName("该服务人员已离职,ID为:" + hmCustomerVo.getStaffId() + ",请联系管理员");
                    return;
                }
                hmCustomerVo.setStaffName(sysUserVo.getNickName());

                HmCustomer update = new HmCustomer();
                BeanUtils.copyProperties(hmCustomerVo, update);
                // 更新数据
                baseMapper.updateById(update);
            }
        });
        return hmCustomerVos;
    }

    private LambdaQueryWrapper<HmCustomer> buildQueryWrapper(HmCustomerBo bo)
    {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<HmCustomer> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getCustomerName()), HmCustomer::getCustomerName, bo.getCustomerName());
        lqw.eq(StringUtils.isNotBlank(bo.getCustomerAge()), HmCustomer::getCustomerAge, bo.getCustomerAge());
        lqw.eq(StringUtils.isNotBlank(bo.getCustomerSex()), HmCustomer::getCustomerSex, bo.getCustomerSex());
        lqw.eq(bo.getCustomerBirth() != null, HmCustomer::getCustomerBirth, bo.getCustomerBirth());
        lqw.eq(StringUtils.isNotBlank(bo.getCustomerBirthday()), HmCustomer::getCustomerBirthday, bo.getCustomerBirthday());
        lqw.eq(StringUtils.isNotBlank(bo.getBirthdayType()), HmCustomer::getBirthdayType, bo.getBirthdayType());
        lqw.eq(StringUtils.isNotBlank(bo.getPolitical()), HmCustomer::getPolitical, bo.getPolitical());
        lqw.eq(StringUtils.isNotBlank(bo.getNativePlace()), HmCustomer::getNativePlace, bo.getNativePlace());
        lqw.eq(StringUtils.isNotBlank(bo.getAddress()), HmCustomer::getAddress, bo.getAddress());
        lqw.eq(StringUtils.isNotBlank(bo.getHobby()), HmCustomer::getHobby, bo.getHobby());
        lqw.eq(StringUtils.isNotBlank(bo.getSpecially()), HmCustomer::getSpecially, bo.getSpecially());
        lqw.eq(StringUtils.isNotBlank(bo.getRetiredUnit()), HmCustomer::getRetiredUnit, bo.getRetiredUnit());
        lqw.eq(StringUtils.isNotBlank(bo.getTitle()), HmCustomer::getTitle, bo.getTitle());
        lqw.eq(StringUtils.isNotBlank(bo.getWeddingDay()), HmCustomer::getWeddingDay, bo.getWeddingDay());
        lqw.eq(StringUtils.isNotBlank(bo.getWeddingDayType()), HmCustomer::getWeddingDayType, bo.getWeddingDayType());
        lqw.eq(StringUtils.isNotBlank(bo.getPhone()), HmCustomer::getPhone, bo.getPhone());
        lqw.eq(bo.getIsBoss() != null, HmCustomer::getIsBoss, bo.getIsBoss());
        lqw.eq(bo.getPension() != null, HmCustomer::getPension, bo.getPension());
        lqw.eq(StringUtils.isNotBlank(bo.getMedicalHistory()), HmCustomer::getMedicalHistory, bo.getMedicalHistory());
        lqw.eq(StringUtils.isNotBlank(bo.getPhysicalCondition()), HmCustomer::getPhysicalCondition, bo.getPhysicalCondition());
        lqw.eq(bo.getIsHealthCare() != null, HmCustomer::getIsHealthCare, bo.getIsHealthCare());
        lqw.eq(StringUtils.isNotBlank(bo.getTakingProducts()), HmCustomer::getTakingProducts, bo.getTakingProducts());
        lqw.eq(StringUtils.isNotBlank(bo.getTakingProductsDesc()), HmCustomer::getTakingProductsDesc, bo.getTakingProductsDesc());
        lqw.eq(StringUtils.isNotBlank(bo.getWhyBuy()), HmCustomer::getWhyBuy, bo.getWhyBuy());
        lqw.eq(StringUtils.isNotBlank(bo.getBuyMethod()), HmCustomer::getBuyMethod, bo.getBuyMethod());
        lqw.eq(StringUtils.isNotBlank(bo.getBuyer()), HmCustomer::getBuyer, bo.getBuyer());
        lqw.eq(bo.getPointsCoin() != null, HmCustomer::getPointsCoin, bo.getPointsCoin());
        lqw.eq(bo.getPointsCoinId() != null, HmCustomer::getPointsCoinId, bo.getPointsCoinId());
        lqw.eq(StringUtils.isNotBlank(bo.getMemberLevel()), HmCustomer::getMemberLevel, bo.getMemberLevel());
        lqw.eq(StringUtils.isNotBlank(bo.getCustomerType()), HmCustomer::getCustomerType, bo.getCustomerType());
        lqw.eq(StringUtils.isNotBlank(bo.getCustomerActivity()), HmCustomer::getCustomerActivity, bo.getCustomerActivity());
        lqw.like(StringUtils.isNotBlank(bo.getStaffName()), HmCustomer::getStaffName, bo.getStaffName());
        lqw.eq(bo.getStaffId() != null, HmCustomer::getStaffId, bo.getStaffId());
        lqw.like(StringUtils.isNotBlank(bo.getStoreName()), HmCustomer::getStoreName, bo.getStoreName());
        lqw.eq(bo.getStoreId() != null, HmCustomer::getStoreId, bo.getStoreId());
        lqw.eq(StringUtils.isNotBlank(bo.getFamilyType()), HmCustomer::getFamilyType, bo.getFamilyType());
        lqw.eq(bo.getFamilyId() != null, HmCustomer::getFamilyId, bo.getFamilyId());
        lqw.like(StringUtils.isNotBlank(bo.getFamilyName()), HmCustomer::getFamilyName, bo.getFamilyName());
        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), HmCustomer::getStatus, bo.getStatus());
        lqw.or().eq(bo.getIsPublic() != null, HmCustomer::getIsPublic, bo.getIsPublic());
        lqw.in(CollectionUtils.isNotEmpty(bo.getStaffIds()), HmCustomer::getStaffId, bo.getStaffIds());
        lqw.orderByDesc(HmCustomer::getStaffId);
        return lqw;
    }

    /**
     * 新增客户信息
     *
     * @param bo 客户信息
     *
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(HmCustomerBo bo)
    {
        HmCustomer add = MapstructUtils.convert(bo, HmCustomer.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag)
        {
            bo.setCustomerId(add.getCustomerId());
        }
        return flag;
    }

    /**
     * 修改客户信息
     *
     * @param bo 客户信息
     *
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(HmCustomerBo bo)
    {
        HmCustomer update = MapstructUtils.convert(bo, HmCustomer.class);
        // 查询当前手机号ID是否与更新id相同,若相同则不校验,若不同则校验手机号是否存在
        List<HmCustomer> hmCustomers = baseMapper.selectList(new LambdaQueryWrapper<HmCustomer>().eq(HmCustomer::getPhone, update.getPhone()));
        if (ObjectUtil.isNotEmpty(hmCustomers) && !Objects.equals(hmCustomers.get(0).getCustomerId(), update.getCustomerId()))
        {
            throw new RuntimeException("当前手机号已存在");
        }
        // 判断是否变更了服务人员,若变更了服务人员,则需要同步销售订单和待办
        HmCustomer hmCustomer = baseMapper.selectById(update.getCustomerId());
        if (hmCustomer.getStaffId() != null && !Objects.equals(hmCustomer.getStaffId(), update.getStaffId()))
        {
            HmCustomerBatchTransferBo bo1 = new HmCustomerBatchTransferBo();
            bo1.setCustomerIds(Collections.singletonList(hmCustomer.getCustomerId()));
            bo1.setToStaffId(update.getStaffId()); // 新员工id
            bo1.setTransferReason("客户管理调整客户服务人员");
            bo1.setRemark("客户管理调整客户服务人员");
            batchTransferCustomers(bo1);
        }
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 修改客户家庭信息
     *
     * @param bo 客户信息
     *
     * @return 是否修改成功
     */
    @Override
    public Boolean updateFamily(HmCustomerBo bo)
    {
        AtomicInteger i = new AtomicInteger();
        if (ObjectUtil.isEmpty(bo.getCustomerList()))
        {
            if ("TC".equals(bo.getEventAction())) // 退出
            {
                if (bo.getCustomerId() == null && bo.getCustomerName() != null)
                {
                    // 删除三代数据
                    // 查询三代familyId
                    HmFamilyVo hmFamilyVo = familyService.queryById(bo.getFamilyId());
                    if (hmFamilyVo != null && StringUtils.isNotBlank(hmFamilyVo.getThreePerson()))
                    {
                        List<Map> list = JSONUtil.toList(hmFamilyVo.getThreePerson(), Map.class);
                        List<Map> familyName = list.stream().filter(item -> !bo.getCustomerName().equals(item.get("userName"))).collect(Collectors.toList());
                        hmFamilyVo.setThreePerson(JSONUtil.toJsonStr(familyName));
                        HmFamilyBo hmFamilyBo = new HmFamilyBo();
                        BeanUtil.copyProperties(hmFamilyVo, hmFamilyBo);

                        familyService.updateByBo(hmFamilyBo);
                        return true;
                    }
                }
                else
                {
                    bo.setFamilyId(null);
                    bo.setFamilyType(null);
                    HmCustomer update = MapstructUtils.convert(bo, HmCustomer.class);
                    return baseMapper.updateById(update) > 0;
                }

            }
            return false;
        }
        else
        {
            if (ObjectUtil.isNotEmpty(bo.getFamilyId()))
            {
                bo.getCustomerList().forEach(customer ->
                {
                    customer.setFamilyId(bo.getFamilyId());
                    HmCustomer update = MapstructUtils.convert(customer, HmCustomer.class);
                    boolean b = baseMapper.updateById(update) > 0;
                    if (b)
                    {
                        i.getAndIncrement();
                    }
                });
            }
            return i.get() > 0;
        }
    }

    /**
     * 新增插入前的数据校验
     */
    private void validEntityBeforeSave(HmCustomer entity)
    {
        //TODO 做一些数据校验,如唯一约束
        // 判断当前用户手机号是否存在,若存在则不允许新增,若不存在则判断姓名是否重复,若重复则新增用户名称增加店铺名称
        List<HmCustomer> hmCustomers = baseMapper.selectList(new LambdaQueryWrapper<HmCustomer>().eq(HmCustomer::getPhone, entity.getPhone()));
        if (ObjectUtil.isNotEmpty(hmCustomers))
        {
            throw new RuntimeException("当前手机号已存在");
        }
        else
        {
            HmCustomerBo bo = new HmCustomerBo();
            bo.setCustomerName(entity.getCustomerName());
            List<HmCustomerVo> hmCustomerVos = queryList(bo);
            Optional.ofNullable(hmCustomerVos).orElse(new ArrayList<>()).forEach(item ->
            {
                if (ObjectUtil.isNotEmpty(item))
                {
                    String storeName = deptService.selectDeptNameByIds(String.valueOf(entity.getStoreId()));
                    // 获取店铺名称
                    entity.setCustomerName(entity.getCustomerName() + "(" + storeName + ")");
                }
            });
        }
    }

    /**
     * 校验并批量删除客户信息信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     *
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid)
    {
        if (isValid)
        {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    public HmCustomerVo selectUserByCustomerName(String phone, String customerName)
    {
        return baseMapper.selectVoOne(new LambdaQueryWrapper<HmCustomer>().eq(HmCustomer::getPhone, phone).eq(HmCustomer::getCustomerName, customerName)
            .eq(HmCustomer::getDelFlag, "0"));
    }

    /**
     * 根据客户id查询客户名称
     *
     * @param customerId 客户ID
     *
     * @return
     */
    @Override
    public String selectCustomerNameById(Long customerId)
    {

        HmCustomerVo hmCustomerVo = DataPermissionHelper.ignore(() ->
        {
            return queryById(customerId);
        });

        if (hmCustomerVo != null)
        {
            return hmCustomerVo.getCustomerName();
        }
        return null;
    }

    /**
     * 根据服务人员ID查询名下所有的客户信息
     *
     * @param staffId
     *
     * @return
     */
    @Override
    public List<HmCustomerVo> queryListByStaffId(Long staffId)
    {
        HmCustomerBo hmCustomerBo = new HmCustomerBo();
        hmCustomerBo.setStaffId(staffId);
        hmCustomerBo.setIsPublic(Boolean.TRUE);
        return DataPermissionHelper.ignore(() -> queryList(hmCustomerBo));
    }

    /**
     * 根据服务人员ID查询名下所有的客户信息
     *
     * @param staffId
     *
     * @return
     */
    @Override
    public List<HmCustomerVo> queryListByStaffIds(Long[] staffId)
    {
        HmCustomerBo hmCustomerBo = new HmCustomerBo();
        hmCustomerBo.setStaffIds(List.of(staffId));
        //        hmCustomerBo.setIsPublic(Boolean.TRUE);
        return DataPermissionHelper.ignore(() -> queryList(hmCustomerBo));
    }

    /**
     * 根据条件分页查询未分配家庭组的客户列表
     *
     * @param customer
     * @param pageQuery
     *
     * @return
     */
    @Override
    public TableDataInfo<HmCustomerVo> selectUnallocatedList(HmCustomerBo customer, PageQuery pageQuery)
    {
        LambdaQueryWrapper<HmCustomer> lqw = Wrappers.<HmCustomer>lambdaQuery().isNull(HmCustomer::getFamilyId);
        if (!LoginHelper.isAdmin())
        {
            lqw.eq(HmCustomer::getStaffId, LoginHelper.getUserId());
        }

        lqw.like(StringUtils.isNotBlank(customer.getCustomerName()), HmCustomer::getCustomerName, customer.getCustomerName());
        lqw.like(StringUtils.isNotBlank(customer.getPhone()), HmCustomer::getPhone, customer.getPhone());
        IPage<HmCustomerVo> hmCustomerVoIPage = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(hmCustomerVoIPage);
    }

    /**
     * 根据条件分页查询分配家庭组的客户列表
     *
     * @param customer
     * @param pageQuery
     *
     * @return
     */
    @Override
    public TableDataInfo<HmCustomerVo> selectLocatedList(HmCustomerBo customer, PageQuery pageQuery)
    {
        LambdaQueryWrapper<HmCustomer> lqw = Wrappers.<HmCustomer>lambdaQuery().eq(HmCustomer::getFamilyId, customer.getFamilyId());
        IPage<HmCustomerVo> hmCustomerVoIPage = baseMapper.selectVoPage(pageQuery.build(), lqw);
        // 查询family是否存在三代信息
        HmFamilyVo hmFamilyVo = familyService.queryById(customer.getFamilyId());
        if (hmFamilyVo.getThreePerson() != null)
        {
            // 将JSON字符串转换成List<Map>
            JSONUtil.toList(hmFamilyVo.getThreePerson(), Map.class).forEach(item ->
            {
                HmCustomerVo hmCustomerVo = new HmCustomerVo();
                hmCustomerVo.setCustomerName(item.get("userName").toString());
                hmCustomerVo.setCustomerBirth(item.get("userBirth").toString());
                hmCustomerVo.setFamilyType(item.get("userType").toString());
                if (hmCustomerVoIPage.getRecords().isEmpty())
                {
                    List<HmCustomerVo> objects = new ArrayList<>();
                    objects.add(hmCustomerVo);
                    hmCustomerVoIPage.setRecords(objects);

                }
                else
                {
                    hmCustomerVoIPage.getRecords().add(hmCustomerVo);

                }
                hmCustomerVoIPage.setTotal(hmCustomerVoIPage.getTotal());
            });
        }
        return TableDataInfo.build(hmCustomerVoIPage);
    }

    /**
     * 查询客户购买记录
     *
     * @param customerId 客户id
     *
     * @return
     */
    @Override
    public HmPurchaseVo queryPurchaseRecordList(Long customerId, PageQuery pageQuery)
    {
        HmPurchaseVo hmPurchaseVo = new HmPurchaseVo();
        HmSaleOrderBo hmSaleOrderBo = new HmSaleOrderBo();
        hmSaleOrderBo.setCustomerId(customerId);
        List<HmSaleOrderVo> hmSaleOrderVos = saleOrderService.queryList(hmSaleOrderBo);
        // 提货商品记录集合
        List<HmSaleOrderPickUpVo> saleOrderCPList = hmSaleOrderVos.stream()
            .flatMap(vo -> CollectionUtils.isEmpty(vo.getHmSaleOrderPickUpVoList()) ? Stream.empty() : vo.getHmSaleOrderPickUpVoList().stream())
            .filter(hmSaleOrderPickUpVo -> "1".equals(hmSaleOrderPickUpVo.getPickUpType()) && "CP".equals(hmSaleOrderPickUpVo.getProductType())) // 提货
            .toList();
        // 回款记录集合
        List<HmSaleOrderPickUpVo> saleOrderPickUpVos = hmSaleOrderVos.stream()
            .flatMap(vo -> CollectionUtils.isEmpty(vo.getHmSaleOrderPickUpVoList()) ? Stream.empty() : vo.getHmSaleOrderPickUpVoList().stream())
            .filter(hmSaleOrderPickUpVo -> "0".equals(hmSaleOrderPickUpVo.getPickUpType())) // 回款
            .toList();
        // 赠品提货记录集合
        List<HmSaleOrderPickUpVo> saleOrderGiftList = hmSaleOrderVos.stream()
            .flatMap(vo -> CollectionUtils.isEmpty(vo.getHmSaleOrderPickUpVoList()) ? Stream.empty() : vo.getHmSaleOrderPickUpVoList().stream())
            .filter(hmSaleOrderPickUpVo -> "1".equals(hmSaleOrderPickUpVo.getPickUpType()) && "ZP".equals(hmSaleOrderPickUpVo.getProductType())) // 提货、
            .toList();
        // 计算总销售金额
        BigDecimal totalAmount = hmSaleOrderVos.stream().map(HmSaleOrderVo::getSaleAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        // 订单数量
        hmPurchaseVo.setRecordNum(hmSaleOrderVos.size());
        // 回款记录条数
        hmPurchaseVo.setRefundNum(saleOrderPickUpVos.size());
        // 总消费金额
        hmPurchaseVo.setTotalConsumption(totalAmount);
        // 总回款金额
        BigDecimal totalRefund = hmSaleOrderVos.stream().map(HmSaleOrderVo::getReturnAmount).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
        hmPurchaseVo.setTotalRefund(totalRefund);
        // 总剩余回款金额
        BigDecimal totalSurplus = hmSaleOrderVos.stream().map(HmSaleOrderVo::getRefundSurplusNum).filter(Objects::nonNull)
            .reduce(BigDecimal.ZERO, BigDecimal::add);
        hmPurchaseVo.setTotalDebt(totalSurplus);
        // 总提货数量
        BigDecimal totalPickUpNum = hmSaleOrderVos.stream().map(HmSaleOrderVo::getPickUpNum).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
        hmPurchaseVo.setPickUpNum(totalPickUpNum);
        // 总剩余提货数量
        BigDecimal totalSurplusPickUpNum = hmSaleOrderVos.stream().map(HmSaleOrderVo::getSurplusNum).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
        hmPurchaseVo.setSurplusNum(totalSurplusPickUpNum);
        // 总评点数量
        BigDecimal totalNum = hmSaleOrderVos.stream().map(HmSaleOrderVo::getGiftNum).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
        hmPurchaseVo.setGiftNum(totalNum);
        // 总剩余评点数量
        BigDecimal totalSurplusNum = hmSaleOrderVos.stream().map(HmSaleOrderVo::getGiftSurplusNum).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
        hmPurchaseVo.setGiftSurplusNum(totalSurplusNum);
        // 总评点提取数量
        BigDecimal totalGiftPickUpNum = hmSaleOrderVos.stream().map(HmSaleOrderVo::getGiftPickUpNum).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
        hmPurchaseVo.setGiftPickUpNum(totalGiftPickUpNum);

        // 销售订单集合
        IPage<HmSaleOrderVo> page = pageQuery.build();
        page.setTotal(hmSaleOrderVos.size());
        page.setRecords(CollUtil.page((int) page.getCurrent() - 1, (int) page.getSize(), hmSaleOrderVos));
        TableDataInfo<HmSaleOrderVo> hmSaleOrderPageList = TableDataInfo.build(page);
        hmPurchaseVo.setSaleOrders(hmSaleOrderPageList);

        // 总回款记录集合
        IPage<HmSaleOrderPickUpVo> refundPage = pageQuery.build();
        refundPage.setTotal(saleOrderPickUpVos.size());
        refundPage.setRecords(CollUtil.page((int) refundPage.getCurrent() - 1, (int) refundPage.getSize(), saleOrderPickUpVos));
        TableDataInfo<HmSaleOrderPickUpVo> hmSaleOrderPickUpPageList = TableDataInfo.build(refundPage);
        hmPurchaseVo.setRefunds(hmSaleOrderPickUpPageList);

        // 总提货记录集合
        IPage<HmSaleOrderPickUpVo> pickUpPage = pageQuery.build();
        pickUpPage.setTotal(saleOrderCPList.size());
        pickUpPage.setRecords(CollUtil.page((int) pickUpPage.getCurrent() - 1, (int) pickUpPage.getSize(), saleOrderCPList));
        TableDataInfo<HmSaleOrderPickUpVo> hmSaleOrderPickUpPageList1 = TableDataInfo.build(pickUpPage);
        hmPurchaseVo.setPickUps(hmSaleOrderPickUpPageList1);

        // 总赠品提货记录集合
        IPage<HmSaleOrderPickUpVo> giftPage = pageQuery.build();
        giftPage.setTotal(saleOrderGiftList.size());
        giftPage.setRecords(CollUtil.page((int) giftPage.getCurrent() - 1, (int) giftPage.getSize(), saleOrderGiftList));
        TableDataInfo<HmSaleOrderPickUpVo> hmSaleOrderPickUpPageList2 = TableDataInfo.build(giftPage);
        hmPurchaseVo.setGiftPickUps(hmSaleOrderPickUpPageList2);

        return hmPurchaseVo;
    }

    @Override
    public List<HmCustomerVo> queryListByIds(List<Long> customerIds)
    {
        if (CollUtil.isEmpty(customerIds))
        {
            return new ArrayList<>();
        }
        List<HmCustomer> customers = baseMapper.selectBatchIds(customerIds);
        return customers.stream().map(c ->
        {
            HmCustomerVo vo = new HmCustomerVo();
            org.springframework.beans.BeanUtils.copyProperties(c, vo);
            return vo;
        }).collect(Collectors.toList());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean batchTransferCustomers(HmCustomerBatchTransferBo bo)
    {
        if (bo.getToStaffId() == null && bo.getNewStoreId() == null)
        {
            throw new ServiceException("新员工和新店铺至少需要指定一个");
        }

        Long operatorId = LoginHelper.getUserId();
        String operatorName = LoginHelper.getLoginUser().getNickname();
        String operatorUsername = LoginHelper.getUserIdStr();

        SysUserVo newStaff = null;
        String newStaffName = null;
        if (bo.getToStaffId() != null && bo.getToStaffId() > 0)
        {
            newStaff = sysUserService.selectUserById(bo.getToStaffId());
            if (newStaff == null)
            {
                throw new ServiceException("指定的新服务员工不存在 (ID: " + bo.getToStaffId() + ")");
            }
            if (!"0".equals(newStaff.getStatus()))
            { // 0: normal, 1: deactivated
                throw new ServiceException("指定的新服务员工已停用/离职，无法分配 (姓名: " + newStaff.getNickName() + ")");
            }
            newStaffName = newStaff.getNickName();
        }

        SysDeptVo newStore = null;
        String newStoreName = null;
        if (bo.getNewStoreId() != null && bo.getNewStoreId() > 0)
        {
            newStore = sysDeptService.selectDeptById(bo.getNewStoreId());
            if (newStore == null)
            {
                throw new ServiceException("指定的新归属店铺不存在 (ID: " + bo.getNewStoreId() + ")");
            }
            if (!"0".equals(newStore.getStatus()))
            { // 0: normal, 1: deactivated
                throw new ServiceException("指定的新归属店铺已停用，无法分配 (名称: " + newStore.getDeptName() + ")");
            }
            newStoreName = newStore.getDeptName();
        }

        List<HmCustomerVo> customersToTransfer = queryListByIds(bo.getCustomerIds());

        if (CollUtil.isEmpty(customersToTransfer))
        {
            throw new ServiceException("未找到任何需要转移的客户");
        }
        // 老已离职员工ID为
        Long oldStaffId = customersToTransfer.get(0).getStaffId();
        List<HmCustomerTransferHistory> historyList = new ArrayList<>();
        Date now = DateUtils.getNowDate();

        for (HmCustomerVo customer : customersToTransfer)
        {
            // Determine transfer type
            String transferType = "";
            boolean staffChanged = bo.getToStaffId() != null && bo.getToStaffId() > 0 && !bo.getToStaffId().equals(customer.getStaffId());
            boolean storeChanged = bo.getNewStoreId() != null && bo.getNewStoreId() > 0 && !bo.getNewStoreId().equals(customer.getStoreId());

            if (staffChanged && storeChanged)
            {
                transferType = "ALL_TRANSFER";
            }
            else if (staffChanged)
            {
                transferType = "STAFF_TRANSFER";
            }
            else if (storeChanged)
            {
                transferType = "STORE_TRANSFER";
            }
            else
            {
                continue;
            }

            HmCustomerTransferHistory history = new HmCustomerTransferHistory();
            history.setCustomerId(customer.getCustomerId());
            history.setCustomerName(customer.getCustomerName());

            history.setOldStaffId(customer.getStaffId());
            history.setOldStaffName(customer.getStaffName());
            history.setOldStoreId(customer.getStoreId());
            history.setOldStoreName(customer.getStoreName());

            history.setNewStaffId(staffChanged ? bo.getToStaffId() : customer.getStaffId());
            history.setNewStaffName(staffChanged ? newStaffName : customer.getStaffName());
            history.setNewStoreId(storeChanged ? bo.getNewStoreId() : customer.getStoreId());
            history.setNewStoreName(storeChanged ? newStoreName : customer.getStoreName());

            history.setTransferType(transferType);
            history.setTransferReason(bo.getTransferReason());
            history.setOperatorId(operatorId);
            history.setOperatorName(operatorName);
            //            history.setCreateBy(operatorUsername);
            history.setCreateTime(now);
            // remark can be set if needed

            historyList.add(history);
        }

        if (CollUtil.isEmpty(historyList))
        {
            throw new ServiceException("没有客户信息发生实际变更");
        }

        Long effectiveNewStaffId = (bo.getToStaffId() != null && bo.getToStaffId() > 0) ? bo.getToStaffId() : null;
        String effectiveNewStaffName = (effectiveNewStaffId != null) ? newStaffName : null;
        Long effectiveNewStoreId = (bo.getNewStoreId() != null && bo.getNewStoreId() > 0) ? bo.getNewStoreId() : null;
        String effectiveNewStoreName = (effectiveNewStoreId != null) ? newStoreName : null;

        int updatedRows = baseMapper.updateCustomerStaffAndStoreBatch(bo.getCustomerIds(), effectiveNewStaffId, effectiveNewStaffName, effectiveNewStoreId, effectiveNewStoreName, operatorUsername, // update_by
            now, // update_time
            now // last_maintain_date
        );

        // 3. 逐一插入获取id,方便后续关联订单和待办记录
        for (HmCustomerTransferHistory history : historyList) {
            customerTransferHistoryService.insert(history);
        }

        // 创建一个映射，以便按客户ID轻松查找新的历史记录ID
        Map<Long, Long> customerIdToHistoryIdMap = historyList.stream()
            .collect(Collectors.toMap(HmCustomerTransferHistory::getCustomerId, HmCustomerTransferHistory::getCustomerTransferHistoryId));

        List<Long> actualCustomerIdsToTransfer = new ArrayList<>(customerIdToHistoryIdMap.keySet());

        // 5. Handle Order Transfer and History
        if ((effectiveNewStaffId != null || effectiveNewStoreId != null))
        {
            // Find orders to be transferred
            List<HmSaleOrder> ordersToTransfer = saleOrderService.selectUnfinishedOrdersByCustomerIds(actualCustomerIdsToTransfer);
            if (CollUtil.isNotEmpty(ordersToTransfer))
            {
                // Create history for them
                List<HmOrderTransferHistory> orderHistoryList = new ArrayList<>();
                for (HmSaleOrder order : ordersToTransfer)
                {
                    // 获取deptName
                    String oldDeptName = deptService.selectDeptNameByIds(order.getSaleDept().toString());
                    HmOrderTransferHistory history = new HmOrderTransferHistory();
                    history.setCustomerTransferHistoryId(customerIdToHistoryIdMap.get(order.getCustomerId()));
                    history.setSaleOrderId(order.getSaleId());
                    history.setCustomerId(order.getCustomerId());
                    history.setOldSaleUser(order.getSaleUser());
                    history.setOldSaleUserName(order.getSaleUserName() == null ? bo.getOldStaffName() : order.getSaleUserName());
                    history.setOldSaleDept(order.getSaleDept());
                    history.setOldSaleDeptName(oldDeptName);
                    history.setNewSaleUser(effectiveNewStaffId);
                    history.setNewSaleUserName(newStaffName);
                    history.setNewSaleDept(effectiveNewStoreId);
                    history.setNewSaleDeptName(newStoreName == null? oldDeptName : newStoreName);
                    history.setOperatorId(operatorId);
                    history.setOperatorName(operatorName);
                    history.setCreateTime(now);
                    orderHistoryList.add(history);
                }
                orderTransferHistoryService.batchInsertHistories(orderHistoryList);

                // 同步更新销售单
                saleOrderService.updateSaleOrderAndTodo(actualCustomerIdsToTransfer, effectiveNewStaffId, effectiveNewStaffName, effectiveNewStoreId, effectiveNewStoreName, operatorUsername, now);
            }
        }

        // 6. Handle Todo Transfer and History
        if (effectiveNewStaffId != null)
        {
            // Find todos to be transferred
            List<HmTodoItems> todosToTransfer = todoItemsService.selectPendingTodosByStaffId(oldStaffId);
            // 增加过滤条件,若不转移其余待办事项则只转移客户数据,即待办事项的customerId在实际需要转移的客户ID列表中

            if (CollUtil.isNotEmpty(todosToTransfer))
            {
                // Create history
                List<HmTodoTransferHistory> todoHistoryList = new ArrayList<>();
                for (HmTodoItems todo : todosToTransfer)
                {
                    HmTodoTransferHistory history = new HmTodoTransferHistory();
                    history.setTodoId(todo.getTodoId());
                    history.setCustomerId(todo.getFollowCustomerId());
                    history.setOldTodoPersonId(todo.getTodoPersonId());
                    history.setOldTodoPersonName(todo.getTodoPersonName() == null ? bo.getOldStaffName() : todo.getTodoPersonName());
                    history.setNewTodoPersonId(effectiveNewStaffId);
                    history.setNewTodoPersonName(newStaffName);
                    history.setOperatorId(operatorId);
                    history.setOperatorName(operatorName);
                    history.setCreateTime(now);
                    todoHistoryList.add(history);
                }
                todoTransferHistoryService.batchInsertHistories(todoHistoryList);

                // 更新待办任务
                todoItemsService.updateTodoItems(oldStaffId, effectiveNewStaffId, effectiveNewStaffName,operatorUsername, now);
            }

        }

        return true;
    }

    /**
     * 加载离职员工列表
     *
     * @param storeId
     *
     * @return
     */
    @Override
    public HmStaffTransferVo resignedStaffCustomersList(Long storeId)
    {
        HmStaffTransferVo result = new HmStaffTransferVo();
        List<SysUserVo> sysUserVos = sysUserService.selectUserListByDept(storeId);

        if (CollUtil.isNotEmpty(sysUserVos))
        {
            List<StaffVo> staffVos = new ArrayList<>();
            sysUserVos.stream().filter(sysUserVo -> "1".equals(sysUserVo.getStatus())).forEach(sysUserVo ->
            {
                StaffVo staffVo = new StaffVo();
                List<HmCustomerVo> hmCustomerVos = queryListByStaffId(sysUserVo.getUserId());
                BeanUtils.copyProperties(sysUserVo, staffVo);
                staffVo.setCustomerList(hmCustomerVos);
                staffVos.add(staffVo);
            });
            // 过滤账号已停用(离职)
            result.setUserLeaveList(staffVos);
        }
        // 过滤正常账号
        result.setUserList(sysUserVos.stream().filter(sysUserVo -> "0".equals(sysUserVo.getStatus())).collect(Collectors.toList()));
        return result;
    }

    /**
     * 认领公池客户。
     *
     * @param customerId 要认领的客户ID
     * @param newStaffId 认领客户的销售人员ID
     * @return 是否认领成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean claimPublicCustomer(Long customerId, Long newStaffId) {
        HmCustomer customer = baseMapper.selectById(customerId);
        if (customer == null) {
            throw new ServiceException("客户不存在。");
        }
        if (Boolean.FALSE.equals(customer.getIsPublic())) {
            throw new ServiceException("该客户目前不是公池客户，无需认领。");
        }

        SysUserVo newStaff = sysUserService.selectUserById(newStaffId);
        if (newStaff == null) {
            throw new ServiceException("认领的服务人员不存在。");
        }
        if (!"0".equals(newStaff.getStatus())) { // 0: normal, 1: deactivated
            throw new ServiceException("认领的服务人员已停用/离职，无法认领客户。");
        }
        // 确保认领员工在客户所属的店铺
        if (!Objects.equals(customer.getStoreId(), newStaff.getDeptId())) {
            throw new ServiceException("认领服务人员必须与客户属于同一店铺。");
        }

        // 1. 更新客户信息：从公池转为私有，并分配新的服务人员
        HmCustomer updateCustomer = new HmCustomer();
        updateCustomer.setCustomerId(customerId);
        updateCustomer.setIsPublic(false); // 不再是公池客户
        updateCustomer.setStaffId(newStaff.getUserId());
        updateCustomer.setStaffName(newStaff.getNickName());
        updateCustomer.setLastMaintainDate(DateUtils.getTime()); // 更新最后维护时间
        updateCustomer.setUpdateBy(LoginHelper.getUserId());
        updateCustomer.setUpdateTime(new Date());
        baseMapper.updateById(updateCustomer);

        // 2. 记录客户转移历史
        HmCustomerTransferHistory history = new HmCustomerTransferHistory();
        history.setCustomerId(customer.getCustomerId());
        history.setCustomerName(customer.getCustomerName());
        history.setOldStaffId(null); // 公池客户旧员工为null
        history.setOldStaffName("公池"); // 标记为从公池认领
        history.setOldStoreId(customer.getStoreId());
        history.setOldStoreName(customer.getStoreName());
        history.setNewStaffId(newStaff.getUserId());
        history.setNewStaffName(newStaff.getNickName());
        history.setNewStoreId(customer.getStoreId());
        history.setNewStoreName(customer.getStoreName());
        history.setTransferType("CLAIM_FROM_PUBLIC_POOL"); // 认领类型
        history.setTransferReason("从公池认领");
        history.setOperatorId(LoginHelper.getUserId());
        history.setOperatorName(LoginHelper.getLoginUser().getNickname());
        history.setCreateTime(new Date());
        history.setStatus("0"); // 正常状态
        customerTransferHistoryService.insert(history);

        // 3. 将该客户名下所有未完成的订单和待办事项转移给新的服务人员
        List<Long> customerIds = Collections.singletonList(customerId);
        Long operatorId = LoginHelper.getUserId();
        String operatorUsername = LoginHelper.getUserIdStr();
        Date now = new Date();

        // 转移订单
        List<HmSaleOrder> unfinishedOrders = saleOrderService.selectUnfinishedOrdersByCustomerIds(customerIds);
        if (CollUtil.isNotEmpty(unfinishedOrders)) {
            List<HmOrderTransferHistory> orderHistoryList = new ArrayList<>();
            for (HmSaleOrder order : unfinishedOrders) {
                String oldDeptName = deptService.selectDeptNameByIds(order.getSaleDept().toString());

                HmOrderTransferHistory orderHistory = new HmOrderTransferHistory();
                orderHistory.setCustomerTransferHistoryId(history.getCustomerTransferHistoryId()); // 关联客户转移历史
                orderHistory.setSaleOrderId(order.getSaleId());
                orderHistory.setCustomerId(order.getCustomerId());
                orderHistory.setOldSaleUser(order.getSaleUser());
                orderHistory.setOldSaleUserName(order.getSaleUserName());
                orderHistory.setOldSaleDept(order.getSaleDept());
                orderHistory.setOldSaleDeptName(oldDeptName);
                orderHistory.setNewSaleUser(newStaff.getUserId());
                orderHistory.setNewSaleUserName(newStaff.getNickName());
                orderHistory.setNewSaleDept(newStaff.getDeptId()); // 订单转移到新员工的店铺
                orderHistory.setNewSaleDeptName(newStaff.getDeptName()); // 订单转移到新员工的店铺名称
                orderHistory.setOperatorId(operatorId);
                orderHistory.setOperatorName(LoginHelper.getLoginUser().getNickname());
                orderHistory.setCreateTime(now);
                orderHistory.setStatus("0");
                orderHistoryList.add(orderHistory);
            }
            orderTransferHistoryService.batchInsertHistories(orderHistoryList);
            // 更新销售订单的归属
            saleOrderService.updateSaleOrderAndTodo(
                customerIds,
                newStaff.getUserId(),
                newStaff.getNickName(),
                newStaff.getDeptId(), // 新店铺ID
                newStaff.getDeptName(), // 新店铺名称
                operatorUsername,
                now
            );
        }

        // 转移待办事项
        List<HmTodoItems> pendingTodos = todoItemsService.selectPendingTodosByCustomerIds(customerIds); // 新增此方法
        if (CollUtil.isNotEmpty(pendingTodos)) {
            List<HmTodoTransferHistory> todoHistoryList = new ArrayList<>();
            for (HmTodoItems todo : pendingTodos) {
                HmTodoTransferHistory todoHistory = new HmTodoTransferHistory();
                todoHistory.setCustomerTransferHistoryId(history.getCustomerTransferHistoryId()); // 关联客户转移历史
                todoHistory.setTodoId(todo.getTodoId());
                todoHistory.setCustomerId(todo.getFollowCustomerId());
                todoHistory.setOldTodoPersonId(todo.getTodoPersonId());
                todoHistory.setOldTodoPersonName(todo.getTodoPersonName());
                todoHistory.setNewTodoPersonId(newStaff.getUserId());
                todoHistory.setNewTodoPersonName(newStaff.getNickName());
                todoHistory.setOperatorId(operatorId);
                todoHistory.setOperatorName(LoginHelper.getLoginUser().getNickname());
                todoHistory.setCreateTime(now);
                todoHistory.setStatus("0");
                todoHistoryList.add(todoHistory);
            }
            todoTransferHistoryService.batchInsertHistories(todoHistoryList);
            // 更新待办任务的归属
            todoItemsService.updateTodoItemsByCustomerIds(
                customerIds,
                newStaff.getUserId(),
                newStaff.getNickName(),
                operatorUsername,
                now
            );
        }

        log.info("客户ID: {} 已成功被认领并分配给服务人员: {}", customerId, newStaff.getNickName());
        return true;
    }

    /**
     * (Internal method) 新增客户转移历史，供定时任务或内部调用。
     * @param history 客户转移历史实体
     * @return 是否新增成功
     */
    @Override
    public Boolean insert(HmCustomerTransferHistory history) {
        return customerTransferHistoryService.insert(history);
    }
}
